<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <title>AI工具导航思维导图</title>
        <script src="https://d3js.org/d3.v7.min.js"></script>
        <style>
            body {
                margin: 0;
                padding: 20px;
                display: flex;
                flex-direction: column;
                align-items: center;
                min-height: 100vh;
                background: #fff;
                box-sizing: border-box;
                overflow: auto;
            }
            #toolbar {
                position: fixed;
                top: 20px;
                left: 20px;
                background: white;
                padding: 10px;
                border-radius: 8px;
                box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
                z-index: 1000;
                display: flex;
                gap: 10px;
            }
            .tool-button {
                padding: 8px 15px;
                border: none;
                border-radius: 4px;
                background: #4169e1;
                color: white;
                cursor: pointer;
                font-size: 14px;
                display: flex;
                align-items: center;
                gap: 5px;
            }
            .tool-button:hover {
                background: #1e90ff;
            }
            .zoom-info {
                padding: 8px 15px;
                background: #f0f0f0;
                border-radius: 4px;
                font-size: 14px;
            }
            #mindmap {
                width: 100%;
                height: 100vh;
                display: flex;
                justify-content: center;
                align-items: center;
                overflow: auto;
                cursor: grab;
            }
            #mindmap:active {
                cursor: grabbing;
            }
            .node {
                cursor: default;
                user-select: none;
                -webkit-user-select: none;
                -moz-user-select: none;
                -ms-user-select: none;
            }
            .node rect {
                fill: white;
                stroke-width: 2px;
                rx: 15;
                ry: 15;
            }
            .node text {
                font: 14px sans-serif;
                dominant-baseline: middle;
                pointer-events: none;
            }
            .link {
                fill: none;
                stroke-width: 2px;
            }
            /* 定义不同层级节点的颜色 */
            .depth-0 rect {
                stroke: #8a2be2;
                fill: white;
            }
            .depth-1 rect {
                stroke: #4169e1; /* 蓝色 */
                fill: #f6f8fe;
            }
            .depth-2 rect {
                stroke: #3cb371; /* 绿色 */
                fill: #f6fef8;
            }
            .depth-3 rect {
                stroke: #ff69b4; /* 粉色 */
                fill: #fef6f8;
            }
            /* 连接线颜色 */
            .link.depth-0 {
                stroke: #8a2be2;
            }
            .link.depth-1 {
                stroke: #4169e1;
            }
            .link.depth-2 {
                stroke: #3cb371;
            }
            .link.depth-3 {
                stroke: #ff69b4;
            }
        </style>
    </head>
    <body>
        <div id="toolbar">
            <button class="tool-button" onclick="zoomIn()">放大</button>
            <button class="tool-button" onclick="zoomOut()">缩小</button>
            <button class="tool-button" onclick="resetZoom()">重置</button>
            <span class="zoom-info" id="zoomLevel">缩放: 100%</span>
            <button class="tool-button" onclick="exportSVG()">导出SVG</button>
            <button class="tool-button" onclick="exportPNG()">导出PNG</button>
        </div>
        <div id="mindmap"></div>
        <script>
            // 添加缩放状态
            let currentScale = 1;
            let currentTranslateX = 0;
            let currentTranslateY = 0;

            // 缩放函数
            function zoomIn() {
                currentScale *= 1.2;
                updateTransform();
            }

            function zoomOut() {
                currentScale *= 0.8;
                updateTransform();
            }

            function resetZoom() {
                currentScale = 1;
                currentTranslateX = 0;
                currentTranslateY = 0;
                updateTransform();
            }

            function updateTransform() {
                const g = d3.select("g");
                // 添加CSS过渡效果使变换更平滑
                g.style(
                    "transition",
                    isDragging ? "none" : "transform 0.05s ease-out"
                ).attr(
                    "transform",
                    `translate(${currentTranslateX},${currentTranslateY}) scale(${currentScale})`
                );
                document.getElementById(
                    "zoomLevel"
                ).textContent = `缩放: ${Math.round(currentScale * 100)}%`;
            }

            // 导出SVG函数
            function exportSVG() {
                const svgData = document.querySelector("svg").outerHTML;
                const blob = new Blob([svgData], { type: "image/svg+xml" });
                const url = URL.createObjectURL(blob);
                const link = document.createElement("a");
                link.href = url;
                link.download = "AI工具导航思维导图.svg";
                document.body.appendChild(link);
                link.click();
                document.body.removeChild(link);
                URL.revokeObjectURL(url);
            }

            // 导出PNG函数
            function exportPNG() {
                // 获取原始SVG元素
                const svgElement = document.querySelector("svg");

                // 创建一个新的SVG数据字符串，确保包含所有必要的属性和样式
                const svgData = `
                    <svg xmlns="http://www.w3.org/2000/svg" 
                         width="${svgElement.viewBox.baseVal.width}" 
                         height="${svgElement.viewBox.baseVal.height}"
                         viewBox="0 0 ${svgElement.viewBox.baseVal.width} ${svgElement.viewBox.baseVal.height}">
                        <defs>
                            <style>
                                .depth-0 rect { stroke: #8a2be2; fill: white; }
                                .depth-1 rect { stroke: #4169e1; fill: #f6f8fe; }
                                .depth-2 rect { stroke: #3cb371; fill: #f6fef8; }
                                .depth-3 rect { stroke: #ff69b4; fill: #fef6f8; }
                                .link.depth-0 { stroke: #8a2be2; }
                                .link.depth-1 { stroke: #4169e1; }
                                .link.depth-2 { stroke: #3cb371; }
                                .link.depth-3 { stroke: #ff69b4; }
                                .node rect { stroke-width: 2px; rx: 15; ry: 15; }
                                .link { fill: none; stroke-width: 2px; }
                                .node text { font: 14px sans-serif; }
                            </style>
                        </defs>
                        <rect width="100%" height="100%" fill="white"/>
                        ${svgElement.innerHTML}
                    </svg>`;

                // 创建Blob
                const blob = new Blob([svgData], {
                    type: "image/svg+xml;charset=utf-8",
                });
                const blobURL = URL.createObjectURL(blob);

                // 创建Image对象
                const img = new Image();
                img.src = blobURL;

                // 图片加载完成后进行处理
                img.onload = function () {
                    // 创建canvas
                    const canvas = document.createElement("canvas");
                    const ctx = canvas.getContext("2d");

                    // 设置canvas尺寸（使用2倍分辨率）
                    const scale = 2;
                    canvas.width = svgElement.viewBox.baseVal.width * scale;
                    canvas.height = svgElement.viewBox.baseVal.height * scale;

                    // 设置白色背景
                    ctx.fillStyle = "white";
                    ctx.fillRect(0, 0, canvas.width, canvas.height);

                    // 缩放以提高清晰度
                    ctx.scale(scale, scale);

                    // 绘制图像
                    ctx.drawImage(img, 0, 0);

                    // 转换为PNG并下载
                    canvas.toBlob(function (pngBlob) {
                        const downloadURL = URL.createObjectURL(pngBlob);
                        const a = document.createElement("a");
                        a.href = downloadURL;
                        a.download = "AI工具导航思维导图.png";
                        document.body.appendChild(a);
                        a.click();
                        document.body.removeChild(a);

                        // 清理资源
                        URL.revokeObjectURL(downloadURL);
                        URL.revokeObjectURL(blobURL);
                    }, "image/png");
                };

                // 错误处理
                img.onerror = function () {
                    console.error("图片加载失败");
                    URL.revokeObjectURL(blobURL);
                };
            }

            // 添加拖动状态变量
            let isDragging = false;
            let startX, startY;
            let velocityX = 0;
            let velocityY = 0;
            let lastX, lastY;
            let animationFrameId;
            let lastTime;

            function applyInertia() {
                if (
                    !isDragging &&
                    (Math.abs(velocityX) > 0.1 || Math.abs(velocityY) > 0.1)
                ) {
                    const now = Date.now();
                    const elapsed = now - lastTime;
                    lastTime = now;

                    // 应用惯性
                    currentTranslateX += velocityX * elapsed;
                    currentTranslateY += velocityY * elapsed;

                    // 减少速度（摩擦力）
                    const friction = 0.95;
                    velocityX *= friction;
                    velocityY *= friction;

                    updateTransform();
                    animationFrameId = requestAnimationFrame(applyInertia);
                }
            }

            d3.select("#mindmap")
                .style("user-select", "none")
                .style("-webkit-user-select", "none")
                .style("-moz-user-select", "none")
                .style("-ms-user-select", "none")
                .on("mousedown", function (event) {
                    event.preventDefault(); // 防止默认的选择行为
                    if (
                        event.target.tagName === "rect" ||
                        event.target.tagName === "text"
                    ) {
                        return;
                    }
                    isDragging = true;
                    startX = event.clientX - currentTranslateX;
                    startY = event.clientY - currentTranslateY;
                    lastX = event.clientX;
                    lastY = event.clientY;
                    lastTime = Date.now();
                    velocityX = 0;
                    velocityY = 0;

                    // 停止任何正在进行的惯性动画
                    if (animationFrameId) {
                        cancelAnimationFrame(animationFrameId);
                    }

                    d3.select(this).style("cursor", "grabbing");
                })
                .on("mousemove", function (event) {
                    if (isDragging) {
                        const now = Date.now();
                        const elapsed = now - lastTime;

                        // 计算新位置
                        currentTranslateX = event.clientX - startX;
                        currentTranslateY = event.clientY - startY;

                        // 计算速度（像素/毫秒）
                        if (elapsed > 0) {
                            velocityX = (event.clientX - lastX) / elapsed;
                            velocityY = (event.clientY - lastY) / elapsed;
                        }

                        lastX = event.clientX;
                        lastY = event.clientY;
                        lastTime = now;

                        updateTransform();
                    }
                })
                .on("mouseup", function () {
                    if (isDragging) {
                        isDragging = false;
                        // 开始惯性动画
                        applyInertia();
                    }
                    d3.select(this).style("cursor", "grab");
                })
                .on("mouseleave", function () {
                    if (isDragging) {
                        isDragging = false;
                        // 开始惯性动画
                        applyInertia();
                    }
                    d3.select(this).style("cursor", "grab");
                });

            // 添加鼠标滚轮缩放
            d3.select("#mindmap").on("wheel", function (event) {
                event.preventDefault();
                if (event.deltaY < 0) {
                    currentScale *= 1.1;
                } else {
                    currentScale *= 0.9;
                }
                updateTransform();
            });

            // 定义思维导图数据
            const data = {
                name: "AI工具导航",
                children: [
                    {
                        name: "AI写作工具",
                        children: [
                            {
                                name: "论文写作",
                                children: [
                                    { name: "笔灵AI论文" },
                                    { name: "稿易AI论文" },
                                    { name: "千笔AI论文" },
                                    { name: "Paperpal" },
                                    { name: "66AI论文" },
                                ],
                            },
                            {
                                name: "创意写作",
                                children: [
                                    { name: "笔灵AI写作" },
                                    { name: "火山写作" },
                                    { name: "墨狐AI" },
                                    { name: "写作猫" },
                                    { name: "彩云小梦" },
                                ],
                            },
                            {
                                name: "商业写作",
                                children: [
                                    { name: "Copy.ai" },
                                    { name: "Jasper" },
                                    { name: "深言达意" },
                                ],
                            },
                        ],
                    },
                    {
                        name: "AI图像工具",
                        children: [
                            {
                                name: "图片生成",
                                children: [
                                    { name: "文心一格" },
                                    { name: "堆友AI" },
                                    { name: "WHEE" },
                                    { name: "Midjourney" },
                                    { name: "Stable Diffusion" },
                                    { name: "DALL·E" },
                                ],
                            },
                            {
                                name: "图片处理",
                                children: [
                                    { name: "美图设计室" },
                                    { name: "Pic Copilot" },
                                    { name: "Remove.bg" },
                                    { name: "Upscayl" },
                                    { name: "Cleanup.pictures" },
                                ],
                            },
                            {
                                name: "设计工具",
                                children: [
                                    { name: "Canva" },
                                    { name: "Figma" },
                                ],
                            },
                        ],
                    },
                    {
                        name: "AI视频工具",
                        children: [
                            {
                                name: "视频创作",
                                children: [
                                    { name: "秒创" },
                                    { name: "SoundView" },
                                    { name: "Runway" },
                                    { name: "Synthesia" },
                                    { name: "Descript" },
                                ],
                            },
                            {
                                name: "视频处理",
                                children: [
                                    { name: "Kapwing" },
                                    { name: "Pictory" },
                                ],
                            },
                        ],
                    },
                    {
                        name: "AI办公工具",
                        children: [
                            {
                                name: "AI幻灯片和演示",
                                children: [
                                    { name: "AiPPT" },
                                    { name: "Beautiful.ai" },
                                    { name: "Tome" },
                                ],
                            },
                            {
                                name: "AI文档工具",
                                children: [
                                    { name: "秘塔写作猫" },
                                    { name: "Notion AI" },
                                    { name: "ChatDoc" },
                                ],
                            },
                            {
                                name: "AI表格工具",
                                children: [
                                    { name: "Excel AI" },
                                    { name: "Sheets AI" },
                                ],
                            },
                        ],
                    },
                    {
                        name: "AI对话聊天",
                        children: [
                            {
                                name: "通用对话",
                                children: [
                                    { name: "智谱清言" },
                                    { name: "豆包" },
                                    { name: "ChatGPT" },
                                    { name: "Claude" },
                                    { name: "Gemini" },
                                ],
                            },
                            {
                                name: "垂直领域",
                                children: [
                                    { name: "ChatLaw" },
                                    { name: "ChatMed" },
                                ],
                            },
                        ],
                    },
                    {
                        name: "AI编程工具",
                        children: [
                            {
                                name: "代码助手",
                                children: [
                                    { name: "豆包MarsCode" },
                                    { name: "GitHub Copilot" },
                                    { name: "Cursor" },
                                    { name: "CodeWhisperer" },
                                ],
                            },
                            {
                                name: "开发工具",
                                children: [
                                    { name: "Replit" },
                                    { name: "Tabnine" },
                                ],
                            },
                        ],
                    },
                    {
                        name: "AI搜索引擎",
                        children: [
                            {
                                name: "智能搜索",
                                children: [
                                    { name: "秘塔AI搜索" },
                                    { name: "Perplexity" },
                                    { name: "You.com" },
                                    { name: "Phind" },
                                ],
                            },
                        ],
                    },
                    {
                        name: "AI音频工具",
                        children: [
                            {
                                name: "音乐生成",
                                children: [
                                    { name: "天谱乐" },
                                    { name: "Soundraw" },
                                    { name: "Mubert" },
                                ],
                            },
                            {
                                name: "语音处理",
                                children: [
                                    { name: "Elevenlabs" },
                                    { name: "Resemble AI" },
                                ],
                            },
                        ],
                    },
                ],
            };

            // 设置基础尺寸
            const baseWidth = 3000;
            const baseHeight = 5000;

            // 创建SVG容器
            const svg = d3
                .select("#mindmap")
                .append("svg")
                .attr("width", "100%")
                .attr("height", "100%")
                .attr("viewBox", `0 0 ${baseWidth} ${baseHeight}`)
                .attr("preserveAspectRatio", "xMidYMid meet");

            // 创建一个包含所有内容的组
            const g = svg.append("g");

            // 创建树形布局
            const tree = d3
                .tree()
                .size([baseHeight * 0.9, baseWidth * 0.5])
                .separation((a, b) => {
                    // 获取节点深度
                    const depth = a.depth;
                    const maxDepth = 3;

                    // 判断是否是最后一级节点
                    const isLastLevel = depth === maxDepth;

                    // 判断节点是否来自同一个父节点
                    const sameParent = a.parent === b.parent;

                    // 为最后一级节点设置较大的固定间距
                    if (isLastLevel) {
                        // 同一父节点下的子节点
                        if (sameParent) {
                            return 3; // 基础单位间距
                        }
                        // 不同父节点下的子节点
                        return 5; // 增加间距以区分不同组
                    }

                    // 非最后一级节点使用递增的间距
                    const baseSpacing = 1 + depth * 0.5;
                    return sameParent ? baseSpacing : baseSpacing * 2;
                });

            // 生成树形数据
            const root = d3.hierarchy(data);
            tree(root);

            // 创建连接线
            const link = g
                .selectAll(".link")
                .data(root.links())
                .join("path")
                .attr("class", (d) => `link depth-${d.source.depth}`)
                .attr(
                    "d",
                    d3
                        .linkHorizontal()
                        .x((d) => d.y)
                        .y((d) => d.x)
                );

            // 创建节点组
            const node = g
                .selectAll(".node")
                .data(root.descendants())
                .join("g")
                .attr("class", (d) => `node depth-${d.depth}`)
                .attr("transform", (d) => `translate(${d.y},${d.x})`);

            // 添加节点矩形
            node.append("rect")
                .attr("x", (d) => {
                    const textLength = d.data.name.length;
                    const width = Math.max(120, textLength * 14);
                    return -width / 2;
                })
                .attr("y", -20)
                .attr("width", (d) => {
                    const textLength = d.data.name.length;
                    return Math.max(120, textLength * 14);
                })
                .attr("height", 40);

            // 添加节点文本
            node.append("text")
                .attr("dy", "0.31em")
                .attr("text-anchor", "middle")
                .text((d) => d.data.name)
                .clone(true)
                .lower()
                .attr("stroke", "white")
                .attr("stroke-width", 3);

            // 计算整体边界
            const bounds = g.node().getBBox();

            // 计算缩放和平移
            const scale =
                Math.min(baseWidth / bounds.width, baseHeight / bounds.height) *
                0.95;

            // 计算居中位置
            const translateX =
                (baseWidth - bounds.width * scale) / 2 - bounds.x * scale;
            const translateY =
                (baseHeight - bounds.height * scale) / 2 - bounds.y * scale;

            // 应用变换
            g.attr(
                "transform",
                `translate(${translateX},${translateY}) scale(${scale})`
            );
        </script>
    </body>
</html>
